package jsc.fuzzysystem.defuzzyficationstrategy;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Hashtable;
import java.util.List;
import java.util.Set;

import jsc.fuzzysystem.FuzzyOutput;
import jsc.fuzzysystem.util.Domain;
import jsc.fuzzysystem.util.Function;
import jsc.fuzzysystem.util.Point;
import jsc.fuzzysystem.util.Reta;
import jsc.fuzzysystem.variable.FuzzyVariable;
import jsc.fuzzysystem.variable.fuzzyset.FuzzySet;
import jsc.fuzzysystem.variable.fuzzyset.Term;


public class ClippedCenterGravityDefuzzyficationStrategy implements DefuzzyficationStrategy{

	private Hashtable<FuzzyVariable, Hashtable<Term, Double>> inputs;
	@Override
	public FuzzyOutput defuzzyfication(
			Hashtable<FuzzyVariable, Hashtable<Term, Double>> inputs) {
		    
		this.inputs = inputs;
		Set<FuzzyVariable> variables = inputs.keySet();
		Hashtable<FuzzyVariable, Double> output = new Hashtable<FuzzyVariable, Double>();
		
		for (FuzzyVariable fuzzyVariable : variables) {
			
			double centroid = calculateCentroid(fuzzyVariable);
			output.put(fuzzyVariable, centroid);
			
		}
		
		return null;
	}
	
	private double calculateCentroid(FuzzyVariable variable){
	
		 Hashtable<Term, Double> map = this.inputs.get(variable);
		 double average = 0.0;
		 List<Function> functions = new ArrayList<Function>();
		 List<FuzzySet> sets = variable.getFuzzySets();
		
		 
		
		 
		 for (Double value : map.values()) {
			average+= value;

		 }
		 
		 average /= map.values().size();
		
		 for(FuzzySet set : sets){
			 functions.add(set.getFunction());
		 }
		
		 List<Reta> retas = buildFunction(functions, average);
		 double integral = 0.0 ;
		 double integralProdutoX = 0.0;
		 
		 for (Reta reta : retas) {
			integral+=reta.integralReta(reta.getBoundMin(), reta.getBoundMax());
			integralProdutoX+=reta.integralProdutoX(reta.getBoundMin(), reta.getBoundMax());
		 }
		 
		return integralProdutoX/integral;
	}
	
	
	private List<Reta> buildFunction(List<Function> functions,double average){
		
		 List<Point> points = new ArrayList<Point>();
		 Domain domain = functions.get(0).getDomain();
		 
		for(int i = 0 ; i < functions.size() ;i++){
			
			for(int j = i+1;j<functions.size();j++){
				
				  points.addAll(functions.get(i).intersection(functions.get(j))); 
			}
		}
		
		for (Point point : points) {
			if(point.getY() >= average){
				points.remove(point);
			}
		}
		
		
		Reta reta = new Reta(0,average,domain.getBoundMin(),domain.getBoundMax());
		List<Reta> retas = new ArrayList<Reta>();
		
		if(points.size() > 0){
			
			
			
			for(int i = 0 ; i < functions.size() ;i++){
				
				
					 points.addAll(functions.get(i).intersection(reta)); 
					  
			}
			
			Object[] sorted = points.toArray();
			Arrays.sort(sorted);
			
			for(int i = 0;i<points.size()-1 ;i++){
				retas.add(new Reta(points.get(i),points.get(i+1)));
			}
			return retas;
		}
		
		
		
		retas.add(reta);
		return retas;
	}
	
	
	

}
